#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import json
import time
import os
from typing import Dict, List, Optional, Any, Tuple

# ONES API 基础配置
ONES_CONFIG = {
    "base_url": os.getenv("ONES_BASE_URL", "https://sz.ones.cn"),
    "email": "360088940@qq.com",
    "password": "",  # 请填入实际密码或从环境变量读取
    
    # 从环境变量获取的信息
    "user_id": os.getenv("ONES_USER_ID", "K5uAS5Nz"),
    "team_uuid": os.getenv("ONES_TEAM_UUID", "Tuq7N74j"), 
    "org_uuid": os.getenv("ONES_ORG_UUID", "67jG3j67"),
    "auth_token": os.getenv("ONES_AUTH_TOKEN", "eyJhbGciOiJSUzI1NiIsImtpZCI6ImVhNWYwZDJhLTk4NmYtNGUyNC01YTFmLWQyMDllYWQ2YTIwNCIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZGVmYXVsdCJdLCJjbGllbnRfaW5mbyI6eyJjbGllbnRfaXAiOiIxMTMuODcuMTYyLjEwNCJ9LCJleHAiOjE3NjQwNDIzMjgsImlhdCI6MTc0ODQ5MDAyOCwianRpIjoiMzI4MTc4OTItYjlhOS00MTFiLTU4ZjItYjMyNzcwODFkMzhkIiwibG9naW5fdGltZSI6MTc0ODQ5MDMyODkyMSwibmJmIjoxNzQ4NDkwMDI4LCJvcmdfdXNlcl91dWlkIjoiSzV1QVM1TnoiLCJvcmdfdXVpZCI6IjY3akczajY3IiwicmVnaW9uX3V1aWQiOiJkZWZhdWx0Iiwic2NvcGVzIjpbIm9wZW5pZCIsIm9mZmxpbmVfYWNjZXNzIiwibGVnYWN5Iiwib25lczpvcmc6ZGVmYXVsdDo2N2pHM2o2NzpLNXVBUzVOeiJdLCJzaWQiOiI5M2JhNGUyZi1lNWMwLTQ4MjItNjI4Ni0zMTQzN2Y4YTdhODUiLCJzdWIiOiJORFZUQXNySDpkZWZhdWx0OjY3akczajY3Oks1dUFTNU56In0.RL-p1spZrA9E3dWTWWapy_NU49uVLZO3S7aF64avuUXzvZFQFJKknrryH3qtJNjuRAMn8QVVlvLYthc3PtGV4DppEWbz_PmVIwlPT51OKh50FJr9xdvFy_wzlH_Q2k_VFJsnphxeTuc7ZM6f8x-GZOp3bs3T7-OFzz2bLoIyc_1g7S07cYh6MNGQOyMiwCaUBcspfxrhSe23Vay_IW4ziMa9KJox6KHlA7oZjjWJUKCGrlx1fk2RvCmOxXuRjnfs2jK7GoIHSx-OgW5BS3gYz6sjmXdXF6dLGE13UfJU4eOiQE4ImFuZylTwHb_kG47yZwa_VH_rpvnWHHhikyT25A")
}

# API端点配置
API_ENDPOINTS = {
    # 认证相关
    "login": "/api/project/auth/login",
    "auth_info": "/project/api/auth/info",
    "logout": "/project/api/auth/logout",
    
    # TestCase相关
    "libraries": "/project/api/project/team/{team_uuid}/testcase/libraries",
    "plans": "/project/api/project/team/{team_uuid}/testcase/plans",
    
    "library_cases": "/project/api/project/team/{team_uuid}/testcase/library/{library_uuid}/cases",
    "library_cases_alt": "/project/api/project/team/{team_uuid}/items/graphql",
    
    "plan_cases": "/project/api/project/team/{team_uuid}/testcase/plan/{plan_uuid}/cases",
    "add_library": "/project/api/project/team/{team_uuid}/testcase/libraries/add",
    "add_testcase": "/project/api/project/team/{team_uuid}/items/add",
}


class OnesAPIClient:
    """ONES API客户端类 - 用于集成功能测试记录"""
    
    def __init__(self, base_url: str = None, user_id: str = None, auth_token: str = None, team_uuid: str = None):
        """
        初始化ONES API客户端
        
        Args:
            base_url: ONES服务器地址，默认使用配置文件中的地址
            user_id: 用户ID，默认使用配置文件中的ID
            auth_token: 认证token，默认使用配置文件中的token
            team_uuid: 团队UUID，默认使用配置文件中的UUID
        """
        self.base_url = base_url or ONES_CONFIG["base_url"]
        self.user_id = user_id or ONES_CONFIG["user_id"]
        self.auth_token = auth_token or ONES_CONFIG["auth_token"]
        self.team_uuid = team_uuid or ONES_CONFIG["team_uuid"]
        
        self.session = requests.Session()
        self.session.headers.update(self._get_headers())
        
    def _get_headers(self) -> Dict[str, str]:
        """获取API请求头"""
        return {
            "Content-Type": "application/json",
            "User-Agent": "OnesAPIClient/1.0",
            "Referer": f"{self.base_url}/",
            "Ones-User-Id": self.user_id,
            "Ones-Auth-Token": self.auth_token
        }
    
    def _build_url(self, endpoint_key: str, **kwargs) -> str:
        """构建API URL"""
        endpoint = API_ENDPOINTS[endpoint_key]
        endpoint = endpoint.format(
            team_uuid=self.team_uuid,
            **kwargs
        )
        return f"{self.base_url}{endpoint}"
    
    def _make_request(self, method: str, url: str, **kwargs) -> Tuple[bool, Any]:
        """
        发起API请求
        
        Returns:
            Tuple[bool, Any]: (是否成功, 响应数据或错误信息)
        """
        try:
            response = self.session.request(method, url, timeout=30, **kwargs)
            
            if response.status_code == 200:
                try:
                    return True, response.json()
                except:
                    return True, response.text
            else:
                return False, {
                    "status_code": response.status_code,
                    "error": response.text
                }
                
        except Exception as e:
            return False, {"error": str(e)}
    
    # ================== 用例库管理 ==================
    
    def get_libraries(self) -> Tuple[bool, Any]:
        """获取用例库列表"""
        url = self._build_url("libraries")
        return self._make_request("GET", url)
    
    def get_library_cases(self, library_uuid: str) -> Tuple[bool, Any]:
        """获取用例库中的测试用例"""
        # 首先尝试直接API
        url = self._build_url("library_cases", library_uuid=library_uuid)
        success, data = self._make_request("GET", url)
        
        if success and data.get("cases"):
            return success, data
            
        # 如果直接API没有返回用例，尝试GraphQL查询
        print(f"直接API返回空用例，尝试GraphQL查询...")
        return self._get_library_cases_graphql(library_uuid)
    
    def _get_library_cases_graphql(self, library_uuid: str) -> Tuple[bool, Any]:
        """使用GraphQL查询获取用例库中的测试用例"""
        url = self._build_url("library_cases_alt")
        
        # GraphQL查询语句
        graphql_query = {
            "query": """
            query {
              testcases(filter: {library_uuid: {equal: "%s"}}) {
                uuid
                name
                desc
                priority
                type
                assign
                module_uuid
                condition
                steps {
                  uuid
                  desc
                  result
                }
                create_time
                update_time
              }
            }
            """ % library_uuid
        }
        
        success, data = self._make_request("POST", url, json=graphql_query)
        
        if success and isinstance(data, dict):
            # 转换GraphQL响应格式
            testcases = data.get("data", {}).get("testcases", [])
            return True, {"cases": testcases}
        
        return success, data
    
    def get_library_cases_with_fallback(self, library_uuid: str) -> Tuple[bool, Any]:
        """获取用例库中的测试用例（带多种尝试方式）"""
        print(f"正在获取用例库 {library_uuid} 的用例...")
        
        # 方式1: 直接API
        url1 = self._build_url("library_cases", library_uuid=library_uuid)
        print(f"尝试方式1 - 直接API: {url1}")
        success1, data1 = self._make_request("GET", url1)
        
        if success1:
            cases = data1.get("cases", [])
            print(f"方式1结果: 获取到 {len(cases)} 个用例")
            if cases:
                return True, data1
        
        # 方式2: 尝试items接口
        url2 = f"{self.base_url}/project/api/project/team/{self.team_uuid}/items"
        print(f"尝试方式2 - Items接口: {url2}")
        
        # 查询参数
        params = {
            "library_uuid": library_uuid,
            "item_type": "testcase"
        }
        
        success2, data2 = self._make_request("GET", url2, params=params)
        if success2:
            items = data2.get("items", []) if isinstance(data2, dict) else []
            print(f"方式2结果: 获取到 {len(items)} 个items")
            if items:
                # 转换格式
                cases = []
                for item in items:
                    case = {
                        "uuid": item.get("uuid"),
                        "name": item.get("name"),
                        "desc": item.get("desc"),
                        "priority": item.get("priority"),
                        "type": item.get("type"),
                        "assign": item.get("assign"),
                        "module_uuid": item.get("module_uuid"),
                        "condition": item.get("condition"),
                        "steps": item.get("steps", []),
                        "create_time": item.get("create_time"),
                        "update_time": item.get("update_time")
                    }
                    cases.append(case)
                return True, {"cases": cases}
        
        # 方式3: GraphQL查询
        print("尝试方式3 - GraphQL查询")
        return self._get_library_cases_graphql(library_uuid)
    
    def create_library(self, name: str, members: Optional[List[str]] = None) -> Tuple[bool, Any]:
        """创建用例库"""
        url = self._build_url("add_library")
        
        payload = {"name": name}
        if members:
            payload["members"] = members
            
        return self._make_request("POST", url, json=payload)
    
    # ================== 测试计划管理 ==================
    
    def get_plans(self) -> Tuple[bool, Any]:
        """获取测试计划列表"""
        url = self._build_url("plans")
        return self._make_request("GET", url)
    
    def get_plan_cases(self, plan_uuid: str) -> Tuple[bool, Any]:
        """获取测试计划中的用例"""
        url = self._build_url("plan_cases", plan_uuid=plan_uuid)
        return self._make_request("GET", url)
    
    # ================== 测试用例管理 ==================
    
    def create_testcase(self, library_uuid: str, name: str, **kwargs) -> Tuple[bool, Any]:
        """创建测试用例"""
        url = self._build_url("add_testcase")
        
        payload = {
            "item_type": "testcase",
            "library_uuid": library_uuid,
            "name": name,
            **kwargs
        }
        
        return self._make_request("POST", url, json=payload)
    
    # ================== 工具方法 ==================
    
    def find_library_by_name(self, name: str) -> Optional[Dict]:
        """根据名称查找用例库"""
        success, data = self.get_libraries()
        if not success:
            return None
            
        libraries = data.get("libraries", [])
        for library in libraries:
            if library.get("name") == name:
                return library
        return None
    
    def find_plan_by_name(self, name: str) -> Optional[Dict]:
        """根据名称查找测试计划"""
        success, data = self.get_plans()
        if not success:
            return None
            
        plans = data.get("plans", [])
        for plan in plans:
            if plan.get("name") == name:
                return plan
        return None
    
    def get_library_stats(self) -> Dict[str, Any]:
        """获取用例库统计信息"""
        success, data = self.get_libraries()
        if not success:
            return {"error": "获取用例库列表失败"}
        
        libraries = data.get("libraries", [])
        stats = {
            "total_libraries": len(libraries),
            "libraries": []
        }
        
        for library in libraries:
            lib_uuid = library.get("uuid")
            lib_name = library.get("name")
            
            # 获取该库的用例数量
            case_success, case_data = self.get_library_cases(lib_uuid)
            case_count = len(case_data.get("cases", [])) if case_success else 0
            
            lib_stats = {
                "uuid": lib_uuid,
                "name": lib_name,
                "cases_count": case_count,
                "create_time": library.get("create_time")
            }
            stats["libraries"].append(lib_stats)
        
        return stats
    
    def get_plan_stats(self) -> Dict[str, Any]:
        """获取测试计划统计信息"""
        success, data = self.get_plans()
        if not success:
            return {"error": "获取测试计划列表失败"}
        
        plans = data.get("plans", [])
        stats = {
            "total_plans": len(plans),
            "plans": []
        }
        
        for plan in plans:
            plan_uuid = plan.get("uuid")
            plan_name = plan.get("name")
            
            # 获取该计划的用例数量
            case_success, case_data = self.get_plan_cases(plan_uuid)
            case_count = len(case_data.get("cases", [])) if case_success else 0
            
            plan_stats = {
                "uuid": plan_uuid,
                "name": plan_name,
                "cases_count": case_count,
                "stage": plan.get("stage"),
                "status": plan.get("plan_status")
            }
            stats["plans"].append(plan_stats)
        
        return stats 